package com.tomcat.container;

import com.tomcat.annotate.JoinPro;
import com.tomcat.annotate.PackageScans;
import com.tomcat.annotate.RequestToMethod;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Objects;

@PackageScans("com.tomcat")
public class ApplicationContext {

    private Class contextClass;

    private String scanPackagePath;

    public ApplicationContext(Class contextClass) {
        this.contextClass = contextClass;
        PackageScans annotation = (PackageScans) contextClass.getAnnotation(PackageScans.class);
        String value = annotation.value();

        scanPackagePath = value;
        String path = value.replace(".", "/");
        ClassLoader classLoader = ApplicationContext.class.getClassLoader();

        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        try {
            this.putSingObjectsBeanAndMapping(file);
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }

    }

    public void putSingObjectsBeanAndMapping(File file) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        if (file.isDirectory()) {
            for (File currFile : Objects.requireNonNull(file.listFiles())) {
                this.putSingObjectsBeanAndMapping(currFile);
            }
        }
        if (file.getName().endsWith(".class")) {
            int i = file.getPath().replace("\\", ".").indexOf(scanPackagePath);
            Class<?> aClass = Class.forName(file.getPath().substring(i).replace("\\", ".").replace(".class", ""));
            boolean annotationPresent = aClass.isAnnotationPresent(JoinPro.class);
            if (annotationPresent) {
                DefaultSingletonBeanRegistry.singletonObjects.put(file.getName().replace(".class", ""), aClass.newInstance());

                Method[] declaredMethods = aClass.getDeclaredMethods();
                for (Method declaredMethod : declaredMethods) {
                    RequestToMethod annotation = declaredMethod.getAnnotation(RequestToMethod.class);
                    if (annotation != null) {
                        DefaultSingletonBeanRegistry.mapping.put(annotation.value(), declaredMethod);
                    }
                }
            }
        }
    }


    public Integer getBeanSize() {
        return DefaultSingletonBeanRegistry.singletonObjects.size();
    }

    public Integer getMappingSize() {
        return DefaultSingletonBeanRegistry.mapping.size();
    }

    public void printMapping() {
        for (String path : DefaultSingletonBeanRegistry.mapping.keySet()) {
            System.out.println(path);
        }
    }

}
